home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / VideoToolbox 96.06.15 / VideoToolboxSources / AtExitToShell.c < prev    next >
Text File  |  1996-06-11  |  6KB  |  136 lines

  1. /*
  2. AtExitToShell.c
  3.  
  4.     void YourFunction(void);
  5.  
  6.     error=AtExitToShell(YourFunction);
  7.  
  8. AtExitToShell(YourFunction) requests that your function be called when the
  9. application quits, i.e. calls the ExitToShell trap, which tells the MacOS that
  10. it's done. Your function must have no arguments and no return value.
  11.  
  12. (MATLAB: If you compile this file as a MEX resource, to be called from MATLAB, 
  13. then your call to AtExitToShell is a request that your function be called when 
  14. the MEX resource is flushed from memory.)
  15.  
  16. Many VideoToolbox routines set up interrupt service routines that must be killed
  17. before the program goes away. We want to kill these whether we quit via exit(),
  18. abort(), or the ExitToShell trap is invoked directly, e.g. if user types "ES"
  19. in MacsBug. The only way to be sure of killing something before the application
  20. goes away is to attach its killer, by patching, to the ExitToShell trap. That's
  21. what's done here.
  22.  
  23. AtExitToShell() is closely modeled on the ANSI function atexit(). I wrote it to
  24. overcome the restrictive implementation of atexit() and _atexit() in CodeWarrior:
  25. they only invoke your functions if the ANSI function exit() is called, NOT if
  26. you call abort(), or the user types "ES" in MacsBug. I think that AtExitToShell
  27. is equivalent to the non-ANSI _atexit() routine provided by the Symantec THINK C
  28. environment.
  29.  
  30. The registration list (of user functions) is last-in, first-out. When you
  31. eventually quit, your functions will be called in reverse of the order in which
  32. you registered them. No checking is made for duplication: the same function may
  33. be registed multiple times, and will be called multiple times.
  34.  
  35. CAUTION: your application's runtime environment (e.g. stdio) will normally have
  36. shut itself down by the time it calls ExitToShell(), so a function scheduled for 
  37. that time should not assume the availability of such services (e.g. printf). 
  38. There's no restriction on the use of MacOS services.
  39.  
  40. MATLAB: the Standard C atexit() and THINK C _atexit() routines should not be 
  41. used in MATLAB code resources, because they aren't designed to handle the
  42. situation of code that may be flushed any time MATLAB executes "clear mex" or
  43. "clear all", at a time unrelated to exiting of the MATLAB application itself. 
  44. Instead, MATLAB provides mexAtExit(), which allows you to register one callback 
  45. per MEX file, which is called when the MEX file is flushed. (The problem with using
  46. mexAtExit, is that it's hard for any particular subroutine to know whether somebody
  47. else has already used up the single available slot in the call-back table.)
  48. In order to make your C subroutines as portable and autonomous as possible, you may
  49. prefer to use this AtExitToShell() which allows you to register lots of callback 
  50. routines, and registers itself, once, with mexAtExit. 
  51.  
  52. CAUTION: Since MATLAB registers only one function per MEX it is important that 
  53. you consistently adopt one strategy. Either make lots of calls to AtExitToShell
  54. (and NONE to mexAtExit), or just one call to mexAtExit. If you call both AtExitToShell
  55. and mexAtExit then one will displace the other in MATLAB's one-entry table.
  56.  
  57. The code to patch ExitToShell is based on examples that appeared in UseNet
  58. csmp-digest-v3-046 by Kevin Bell (kbell@cs.utexas.edu) and Bill Hofmann
  59. (wdh@netcom.com) in response to a query by Steve Coy (stevec@jolt.mpx.com.au)
  60.  
  61. HISTORY:
  62. 10/27/94 dgp wrote the ExitToShell patch, based on code from UseNet csmp-digest.
  63. 6/17/95 dgp wrote AtExitToShell.c
  64. 7/1/95 dgp made compatible with pre-universal apple headers. 
  65.     Disable if MATLAB is true. Added comments about MATLAB. 
  66. 7/17/95 dgp made compatible with pre-universal headers
  67. 4/19/96 dgp call mexAtExit(). I know this is ok for PPC, but may not work for 68k.
  68. 6/10/96 dgp fixed initialization error when MATLAB is true.
  69. 6/10/96 dgp added a couple paragraphs explaining its use in MATLAB MEX files.
  70. 6/11/96 dgp In response to concerns raised by David Brainard, I added text above
  71.         warning about the danger of calling BOTH AtExitToShell and mexAtExit, and
  72.         I made the A5 stuff conditional on !MATLAB.
  73. */
  74. #include "VideoToolbox.h"
  75. #ifndef __TRAPS__
  76.     #include <Traps.h>    // _ExitToShell
  77. #endif
  78. #include <SegLoad.h>    // ExitToShell()
  79. #if UNIVERSAL_HEADERS
  80.     typedef UniversalProcPtr TrapAddressType;
  81. #else
  82.     #define UniversalProcPtr ProcPtr
  83.     #define NewRoutineDescriptor(a,b,c) a
  84.     typedef long TrapAddressType;
  85. #endif
  86. static pascal void MyExitToShell(void);
  87. #define FUNCTIONS 35
  88. static UniversalProcPtr oldExitToShellTrapAddress=NULL;    // save address of real ExitToShell trap.
  89. static void (*userFunction[FUNCTIONS])(void);    // table of user functions to be called at exit.
  90.  
  91. int AtExitToShell(void (*userFunctionPtr)(void))
  92. {
  93.     #if !MATLAB
  94.         UniversalProcPtr myExitToShellUPP;
  95.     #endif
  96.     int i;
  97.     static Boolean firstTime=1;
  98.  
  99.     if(firstTime){
  100.         #if !MATLAB
  101.             myExitToShellUPP=NewRoutineDescriptor((ProcPtr)MyExitToShell
  102.                 ,kPascalStackBased,GetCurrentISA());
  103.             oldExitToShellTrapAddress=(UniversalProcPtr)GetToolTrapAddress(_ExitToShell);
  104.             SetToolTrapAddress((TrapAddressType)myExitToShellUPP,_ExitToShell);
  105.         #else
  106.             // Ask MATLAB to call MyExitToShell just before disposing of our MEX resource.
  107.             mexAtExit((void *)MyExitToShell);
  108.         #endif
  109.         for(i=0;i<FUNCTIONS;i++)userFunction[i]=NULL;
  110.         firstTime=0;
  111.     }
  112.     for(i=0;i<FUNCTIONS;i++)if(userFunction[i]==NULL){
  113.         userFunction[i]=userFunctionPtr;
  114.         return 0;    // success
  115.     }
  116.     return 1;        // failure: the table's already full
  117. }
  118.  
  119. static pascal void MyExitToShell(void)
  120. {
  121.     int i;
  122.     
  123.     #if !MATLAB
  124.         SetCurrentA5();
  125.         SetToolTrapAddress((TrapAddressType)oldExitToShellTrapAddress,_ExitToShell);
  126.     #endif
  127.  
  128.     for(i=FUNCTIONS-1;i>=0;i--)if(userFunction[i]!=NULL){
  129.         (*userFunction[i])();
  130.     }
  131.  
  132.     #if !MATLAB
  133.         ExitToShell();
  134.     #endif
  135. }
  136.